/*
 * CS522 Program 2
 * Benchmarks for MPI_Reduce 
 * */

#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#include <sys/time.h>

#define ITERS 2
#define TAG 13

int main(int argc, char *argv[]){
    int msg_size_bytes = 0; //in bytes
    int msg_size_int = 0;
    int iterations = ITERS;
    int *msg;
    int *recv_buf;
    int i = 0;
    double start_time, end_time;
    int my_rank, num_nodes;
    int input_num_nodes;

    msg_size_bytes = 8;

    msg_size_int = msg_size_bytes / 4;
    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
    MPI_Comm_size(MPI_COMM_WORLD, &num_nodes);

    //allocate msg
    msg = (int *) malloc(msg_size_int * sizeof(int));
    if (msg == NULL) {
        printf("msg allocation failed \n");
        MPI_Abort(MPI_COMM_WORLD, 1);
    }

    //allocate recv_buf
    recv_buf = (int *) malloc(msg_size_int * sizeof(int));
    if (recv_buf == NULL) {
        printf("recv_buf allocation failed \n");
        MPI_Abort(MPI_COMM_WORLD, 1);
    }   


    //initialize msg and recv_buf
    for(i = 0; i < msg_size_int; i++) {
        msg[i] = i;
    }
    for (i = 0; i < msg_size_int; i++) {
        recv_buf[i] = -1;
    }

    if (my_rank == 0) {
        start_time = MPI_Wtime();
    }

    //send msg and receive
    for (i = 0; i < iterations; i++) {
        MPI_Reduce(&msg[0], &recv_buf[0], msg_size_int, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
/*        if (my_rank == 0) {
            int j = 0;
            for (j = 0; j < msg_size_int; j++) {
                printf("%d ",recv_buf[j]);
            }
            printf("round %d end\n", i);       
       }
*/       
    }

    //output time
    if (my_rank == 0) {
        end_time = MPI_Wtime();
        printf("msg size (bytes): %d , iterations %d: total time: %f, latency: %f \n", msg_size_bytes, iterations, end_time - start_time, (end_time - start_time)/iterations);
    }

    //free
    free(recv_buf);
    free(msg);
    MPI_Finalize();
    return 0;
}
